package io.choerodon.oauth.security.sso.auth;

import static org.hzero.sso.core.constant.OAuthParameters.*;

import java.util.Map;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.hzero.core.util.UUIDUtils;
import org.hzero.oauth.security.config.SecurityProperties;
import org.hzero.sso.auth.AuthAttributes;
import org.hzero.sso.auth.AuthAuthenticationProvider;
import org.hzero.sso.core.common.config.SsoConfigManager;
import org.hzero.sso.core.domain.Domain;
import org.hzero.sso.core.exception.SsoServerException;
import org.hzero.sso.core.service.SsoUserDetailsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

/**
 * @author scp
 * @since 2022/11/4
 */
@Component
@Primary
public class C7nAuthAuthenticationProvider extends AuthAuthenticationProvider {
    private static final Logger LOGGER = LoggerFactory.getLogger(C7nAuthAuthenticationProvider.class);

    @Autowired
    private SsoConfigManager ssoConfigManager;
    @Autowired
    private SecurityProperties securityProperties;

    public C7nAuthAuthenticationProvider(SsoUserDetailsService userDetailsService) {
        super(userDetailsService);
    }

    /**
     * 向认证服务器请求令牌
     */
    protected String exchangeForToken(final HttpServletRequest request, final Domain domain) {
        // 授权码
        String code = request.getParameter(CODE);
        if (StringUtils.isBlank(code)) {
            LOGGER.error("authorization code not found in request parameter");
            throw new SsoServerException("authorization code not found");
        }

        MultiValueMap<String, Object> parameters = new LinkedMultiValueMap<>();
        parameters.add(GRANT_TYPE, "authorization_code");
        parameters.add(CLIENT_ID, domain.getSsoClientId());
        parameters.add(CLIENT_SECRET, domain.getSsoClientPwd());
        parameters.add(REDIRECT_URI, domain.getClientHostUrl());
        parameters.add(DEVICE_ID, UUIDUtils.generateUUID());
        parameters.add(CODE, code);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        HttpEntity<Object> formEntity = new HttpEntity<>(parameters, headers);

        // 获取 token 的地址
        String tokenUrl = ssoConfigManager.getConfigValue(domain, AuthAttributes.CONFIG_FIELD_TOKEN_URL);
        if (StringUtils.isBlank(tokenUrl)) {
            tokenUrl = domain.getSsoServerUrl().endsWith("token") ? domain.getSsoServerUrl() : domain.getSsoServerUrl() + "/oauth/token";
            request.getSession().setAttribute("default-success-url", securityProperties.getLogin().getSuccessUrl());
        }
        LOGGER.info("formEntity{},{},{}", domain.getSsoClientId(), domain.getSsoClientPwd(), code);
        Map<String, Object> map = exchange(tokenUrl, HttpMethod.POST, formEntity);

        return (String) map.get(ACCESS_TOKEN);
    }
}
